﻿using System.Collections.Generic;
using System.Text;
using System.Reflection;
using DO.DreamOnTrader.Quote;

namespace DO.DreamOnTrader.Indicator
{

	/// <summary>
	/// 指標基本類別，及pool
	/// </summary>
	public abstract class TechnicalIndicator : IIndicator
	{
		#region ==========物件變數及方法

		/// <summary>
		/// 加到pool中各指標中的key值名稱
		/// </summary>
		protected abstract string[] Keys { get; }

		/// <summary>
		/// 指標加到pool的索引值
		/// </summary>
		/// <returns></returns>
		public virtual string Index()
		{
			StringBuilder hashStr = new StringBuilder(this.GetType().Name);
			hashStr.Append("(");

			for (int i = 0; i < Keys.Length; i++)
			{
				if (i > 0) hashStr.Append(",");
				PropertyInfo pro = (PropertyInfo)this.GetType().GetProperty(Keys[i]);
				hashStr.Append(pro.Name + ":" + pro.GetValue(this, null));
			}
			hashStr.Append(")");

			return hashStr.ToString();
		}

		/// <summary>
		/// 接收到kbar的處理
		/// </summary>
		/// <param name="kbar"></param>
		private void compute(KBar kbar)
		{
			Formula(kbar);
			if (takeKBar != null)
				takeKBar(kbar);
		}

		/// <summary>
		/// 指標的邏輯計算
		/// </summary>
		/// <param name="kbar"></param>
		protected abstract void Formula(KBar kbar);

		private event BuildingKBarEventHandler takeKBar;

		#endregion

		#region ===========靜態方法及變數
		static ITickBuilder tickSource;
		/// <summary>
		/// 設定ticks builder的來源
		/// </summary>
		public static ITickBuilder TickSource
		{
			set
			{
				if (tickSource != null)
					tickSource.BuildingTick -= new BuildingTickEventHandler(comute);
				tickSource = value;
				tickSource.BuildingTick += new BuildingTickEventHandler(comute);
			}
			get { return tickSource; }
		}

		static IKBarBuilder kBarSource;
		/// <summary>
		/// 設定kbar builder的來源
		/// </summary>
		public static IKBarBuilder KBarSource
		{
			set
			{
				if (kBarSource != null)
					kBarSource.BuildingKBar -= new BuildingKBarEventHandler(comute);
				kBarSource = value;
				kBarSource.BuildingKBar += new BuildingKBarEventHandler(comute);
			}
			get { return kBarSource; }
		}

		/// <summary>
		/// kbar報價pool
		/// </summary>
		static Dictionary<int, KBarComputer> KbarPool = new Dictionary<int, KBarComputer>();

		/// <summary>
		/// 將傳入的指標及kcomputer加入Pool中，並指定其事件
		/// </summary>
		/// <param name="tech"></param>
		/// <returns></returns>
		protected static void Add(ref KBarComputer kbc, TechnicalIndicator tech)
		{
			lock (Pool)
			{
				string key = tech.Index();
				if (Pool.ContainsKey(key))
				{
					kbc = KbarPool[kbc.HuringMin];
					tech = Pool[key];
				}
				else
				{
					lock (KbarPool)
					{
						if (KbarPool.ContainsKey(kbc.HuringMin))
						{
							kbc = KbarPool[kbc.HuringMin];
						}
						else
						{
							KbarPool.Add(kbc.HuringMin, kbc);
						}
					}
					kbc.BuildingKBar += new BuildingKBarEventHandler(tech.compute);
					Pool.Add(key, tech);
				}
			}
		}

		protected static void Add(int _huring, TechnicalIndicator tech)
		{
			KBarComputer kc = new KBarComputer(_huring);
			Add(ref kc, tech);
		}

		/// <summary>
		/// 傳入TICK，以計算
		/// </summary>
		/// <param name="ti"></param>
		protected static void comute(Tick tick)
		{
			lock (KbarPool)
			{
				//Partitioner.Create<Dictionary<int, KBarComputer>>(KbarPool, 10);
				//Parallel.ForEach<KeyValuePair<int, KBarComputer>>(KbarPool, KeyValue =>
				//{IEnumerable
				//    KeyValue.Value.compute(tick);
				//});
				foreach (KeyValuePair<int, KBarComputer> KeyValue in KbarPool)
				{
					KeyValue.Value.compute(tick);
				}
			}
		}

		/// <summary>
		/// 傳入KBAR計算
		/// </summary>
		/// <param name="kb"></param>
		public static void comute(KBar kbar)
		{
			lock (KbarPool)
			{
				//Parallel.ForEach<KeyValuePair<int, KBarComputer>>(KbarPool, KeyValue =>
				//{
				//    KeyValue.Value.compute(kbar);
				//});
				foreach (KeyValuePair<int, KBarComputer> KeyValue in KbarPool)
				{
					KeyValue.Value.compute(kbar);
				}
			}
		}


		/// <summary>
		/// 各指標的pool
		/// </summary>
		static Dictionary<string, TechnicalIndicator> Pool = new Dictionary<string, TechnicalIndicator>();

		/// <summary>
		/// 將傳入的指標加入Pool中，如果己有同樣的指標則不加入
		/// </summary>
		/// <param name="tech"></param>
		/// <returns></returns>
		protected static T Add<T>(ref T tech) where T : TechnicalIndicator
		{
			lock (Pool)
			{
				string key = tech.Index();
				if (Pool.ContainsKey(key))
				{
					return (T)Pool[key];
				}
				else
				{
					Pool.Add(key, tech);
					return tech;
				}
			}
		}

		/// <summary>
		/// 清除pool
		/// </summary>
		public static void Clear()
		{
			lock (Pool)
			{
				Pool.Clear();
			}

			lock (KbarPool)
			{
				KbarPool.Clear();
			}
		}

		#endregion

		#region IIndicator 成員

		public abstract float getValue();

		public float getValue(Tick tick)
		{
			return getValue();
		}

		public float getValue(KBar kbar)
		{
			return getValue();
		}

		public virtual string Label()
		{
			return Index();
		}

		public override string ToString()
		{
			return Label() + ":" + getValue();
		}

		#endregion
	}
}
